1 #include <CoreFoundation/CoreFoundation.h>
2 #include <CoreServices/CoreServices.h>
3 #import "GetMetadataForHTMLLog.h"
4 #import <AIUtilities/NSCalendarDate+ISO8601Parsing.h>
7 Relevant keys from MDItem.h we use or may want to use:
9 @constant kMDItemContentCreationDate
10 This is the date that the contents of the file were created,
11 has an application specific semantic.
14 @constant kMDItemTextContent
15 Contains the text content of the document. Type is a CFString.
17 @constant kMDItemDisplayName
18 This is the localized version of the LaunchServices call
19 LSCopyDisplayNameForURL()/LSCopyDisplayNameForRef().
21 @const kMDItemInstantMessageAddresses
22 Instant message addresses for this item. Type is an Array of CFStrings.
25 /* -----------------------------------------------------------------------------
26 Get metadata attributes from file
28 This function's job is to extract useful information your file format supports
29 and return it as a dictionary
30 ----------------------------------------------------------------------------- */
32 Boolean GetMetadataForXMLLog(NSMutableDictionary *attributes, NSString *pathToFile);
33 NSString *GetTextContentForXMLLog(NSString *pathToFile);
35 Boolean GetMetadataForFile(void* thisInterface,
36 CFMutableDictionaryRef attributes,
37 CFStringRef contentTypeUTI,
38 CFStringRef pathToFile)
40 /* Pull any available metadata from the file at the specified path */
41 /* Return the attribute keys and attribute values in the dict */
42 /* Return TRUE if successful, FALSE if there was no data provided */
44 Boolean success = FALSE;
45 NSAutoreleasePool *pool;
46 pool = [[NSAutoreleasePool alloc] init];
48 if (CFStringCompare(contentTypeUTI, (CFStringRef)@"com.adiumx.htmllog", kCFCompareBackwards) == kCFCompareEqualTo) {
49 success = GetMetadataForHTMLLog((NSMutableDictionary *)attributes, (NSString *)pathToFile);
50 } else if (CFStringCompare(contentTypeUTI, (CFStringRef)@"com.adiumx.xmllog", kCFCompareBackwards) == kCFCompareEqualTo) {
51 success = GetMetadataForXMLLog((NSMutableDictionary *)attributes, (NSString *)pathToFile);
53 NSLog(@"We were passed %@, of type %@, which is an unknown type",pathToFile,contentTypeUTI);
62 * @brief Copy the text content for a file
64 * This is the text which would be the kMDItemTextContent for the file in Spotlight.
66 * @param contentTypeUTI The UTI type. If NULL, the extension of pathToFile will be used
67 * @param pathToFile The full path to the file
69 * @result The kMDItemTextContent. Follows the Copy rule.
71 CFStringRef CopyTextContentForFile(CFStringRef contentTypeUTI,
72 CFStringRef pathToFile)
74 NSAutoreleasePool *pool;
75 CFStringRef textContent;
76 pool = [[NSAutoreleasePool alloc] init];
78 //Deteremine the UTI type if we weren't passed one
79 if (contentTypeUTI == NULL) {
80 if (CFStringCompare((CFStringRef)[(NSString *)pathToFile pathExtension],
82 (kCFCompareBackwards | kCFCompareCaseInsensitive)) == kCFCompareEqualTo) {
83 contentTypeUTI = CFSTR("com.adiumx.xmllog");
84 } else if (CFStringCompare((CFStringRef)[(NSString *)pathToFile pathExtension],
86 (kCFCompareBackwards | kCFCompareCaseInsensitive)) == kCFCompareEqualTo) {
87 contentTypeUTI = CFSTR("com.adiumx.xmllog");
89 //Treat all other log extensions as HTML logs (plaintext will come out fine this way, too)
90 contentTypeUTI = CFSTR("com.adiumx.htmllog");
94 if (CFStringCompare(contentTypeUTI, CFSTR("com.adiumx.htmllog"), kCFCompareBackwards) == kCFCompareEqualTo) {
95 textContent = (CFStringRef)GetTextContentForHTMLLog((NSString *)pathToFile);
96 } else if (CFStringCompare(contentTypeUTI, (CFStringRef)@"com.adiumx.xmllog", kCFCompareBackwards) == kCFCompareEqualTo) {
97 textContent = (CFStringRef)GetTextContentForXMLLog((NSString *)pathToFile);
101 NSLog(@"We were passed %@, of type %@, which is an unknown type",pathToFile,contentTypeUTI);
104 if (textContent) CFRetain(textContent);
111 * @brief get metadata for an XML file
113 * This function gets the metadata contained within a universal chat log format file
114 * @param attributes The dictionary in which to store the metadata
115 * @param pathToFile The path to the file to index
117 * @result true if successful, false if not
119 Boolean GetMetadataForXMLLog(NSMutableDictionary *attributes, NSString *pathToFile)
122 NSXMLDocument *xmlDoc;
124 NSURL *furl = [NSURL fileURLWithPath:(NSString *)pathToFile];
125 xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:furl
126 options:NSXMLNodePreserveCDATA
131 NSArray *authorsArray = [xmlDoc nodesForXPath:@"//message/@sender"
133 NSSet *duplicatesRemover = [NSSet setWithArray: authorsArray];
134 authorsArray = [duplicatesRemover allObjects];
136 [(NSMutableDictionary *)attributes setObject:authorsArray
137 forKey:(NSString *)kMDItemAuthors];
139 NSArray *contentArray = [xmlDoc nodesForXPath:@"//message//text()"
141 NSString *contentString = [contentArray componentsJoinedByString:@" "];
143 [attributes setObject:contentString
144 forKey:(NSString *)kMDItemTextContent];
146 NSString *serviceString = [[[xmlDoc rootElement] attributeForName:@"service"] objectValue];
147 if(serviceString != nil)
148 [attributes setObject:serviceString
149 forKey:@"com_adiumX_service"];
151 NSArray *children = [[xmlDoc rootElement] children];
152 NSCalendarDate *startDate = nil, *endDate = nil;
154 if ([children count]) {
157 dateStr = [[(NSXMLElement *)[children objectAtIndex:0] attributeForName:@"time"] objectValue];
158 startDate = (dateStr ? [NSCalendarDate calendarDateWithString:dateStr] : nil);
160 [(NSMutableDictionary *)attributes setObject:startDate
161 forKey:(NSString *)kMDItemContentCreationDate];
163 dateStr = [[(NSXMLElement *)[children objectAtIndex:0] attributeForName:@"time"] objectValue];
164 endDate = (dateStr ? [NSCalendarDate calendarDateWithString:dateStr] : nil);
166 [(NSMutableDictionary *)attributes setObject:[NSNumber numberWithInt:[endDate timeIntervalSinceDate:startDate]]
167 forKey:(NSString *)kMDItemDurationSeconds];
170 NSString *accountString = [[[xmlDoc rootElement] attributeForName:@"account"] objectValue];
172 [attributes setObject:accountString
173 forKey:@"com_adiumX_chatSource"];
174 NSMutableArray *otherAuthors = [authorsArray mutableCopy];
175 [otherAuthors removeObject:accountString];
176 //pick the first author for this. likely a bad idea
177 if (startDate && [otherAuthors count]) {
178 NSString *toUID = [otherAuthors objectAtIndex:0];
179 [attributes setObject:[NSString stringWithFormat:@"%@ on %@",toUID,[startDate descriptionWithCalendarFormat:@"%y-%m-%d"
182 forKey:(NSString *)kMDItemDisplayName];
184 [otherAuthors release];
187 [attributes setObject:@"Chat log"
188 forKey:(NSString *)kMDItemKind];
198 NSString *killXMLTags(NSString *inString)
200 NSScanner *scan = [NSScanner scannerWithString:inString];
201 NSString *tempString = nil;
202 NSMutableString *ret = [NSMutableString string];
205 while(![scan isAtEnd]){
207 [scan scanUpToString:@"<" intoString:&tempString];
208 if(tempString != nil)
209 [ret appendFormat:@"%@ ", tempString];
210 [scan scanString:@"<" intoString:nil];
211 [scan scanUpToString:@">" intoString:&tempString];
212 if([tempString hasPrefix:@"br"])
213 [ret appendString:@"\n"];
214 [scan scanString:@">" intoString:nil];
218 NSRange searchRange = NSMakeRange(rng.location+1, [ret length]-rng.location-1);
219 rng = [ret rangeOfString:@"<" options:0 range:searchRange];
221 [ret replaceCharactersInRange: rng withString: @"<"];
222 } while (rng.length > 0);
225 NSRange searchRange = NSMakeRange(rng.location+1, [ret length]-rng.location-1);
226 rng = [ret rangeOfString:@">" options:0 range:searchRange];
228 [ret replaceCharactersInRange: rng withString: @">"];
229 } while (rng.length > 0);
232 NSRange searchRange = NSMakeRange(rng.location+1, [ret length]-rng.location-1);
233 rng = [ret rangeOfString:@"&" options:0 range:searchRange];
235 [ret replaceCharactersInRange: rng withString: @"&"];
236 } while (rng.length > 0);
240 NSString *GetTextContentForXMLLog(NSString *pathToFile)
243 NSURL *furl = [NSURL fileURLWithPath:(NSString *)pathToFile];
244 NSString *contentString;
245 NSXMLDocument *xmlDoc;
246 xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:furl
247 options:NSXMLNodePreserveCDATA
249 NSArray *contentArray = [xmlDoc nodesForXPath:@"//message//text()"
251 contentString = [contentArray componentsJoinedByString:@" "];
253 return contentString;